package storage

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

func NewCredential(accessKeyId, accessKeySecret string) credentials.CredentialsProvider {
	credential := credentials.NewStaticCredentialsProvider(accessKeyId, accessKeySecret) // 静态
	// credential := credentials.NewEcsRoleCredentialsProvider(func(options *credentials.EcsRoleCredentialsProviderOptions) {
	// }) // ecsRole
	// credential := credentials.NewEnvironmentVariableCredentialsProvider()                // 环境变量 OSS_ACCESS_KEY_ID|OSS_ACCESS_KEY_SECRET|OSS_SESSION_TOKEN
	// credential := credentials.NewProcessCredentialsProvider(command) // Process
	// credential := credentials.NewCredentialsFetcherProvider(credentials.CredentialsFetcher{}) // Fetcher

	return credential
}
func NewAlibaba(ctx context.Context, credential credentials.CredentialsProvider, region, bucket string) *Alibaba {
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credential).
		WithRegion(region)

	return &Alibaba{
		ctx:    ctx,
		client: oss.NewClient(cfg),
		bucket: bucket,
	}
}

type Alibaba struct {
	ctx    context.Context
	client *oss.Client
	bucket string
}

// ## Storage

func (r *Alibaba) Upload(filePath string, object string) error {
	result, err := r.ObjectStore(filePath, object)
	fmt.Println(result)
	return err
}

// ## OSS

// ### Bucket
// #### 增删改查

func (r *Alibaba) BucketList() {
	p := r.client.NewListBucketsPaginator(&oss.ListBucketsRequest{})

	var i int

	for p.HasNext() {
		i++
		page, err := p.NextPage(r.ctx)
		if err != nil {
			log.Fatalf("failed to get page %v, %v", i, err)
		}

		for _, b := range page.Buckets {
			fmt.Printf("Bucket:%v, %v, %v\n", oss.ToString(b.Name), oss.ToString(b.StorageClass), oss.ToString(b.Location))
		}
	}
}

// ### Object
// #### 增删改查

func (r *Alibaba) ObjectList() {
	p := r.client.NewListObjectsV2Paginator(&oss.ListObjectsV2Request{
		Bucket: oss.Ptr(r.bucket),
	})

	var i int
	for p.HasNext() {
		i++

		page, err := p.NextPage(context.TODO())
		if err != nil {
			log.Fatalf("failed to get page %v, %v", i, err)
		}

		for _, obj := range page.Contents {
			fmt.Printf("Object:%v, %v, %v\n", oss.ToString(obj.Key), obj.Size, oss.ToTime(obj.LastModified))
		}
	}
}
func (r *Alibaba) ObjectStore(filePath, object string) (*oss.PutObjectResult, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return nil, err
	}
	defer func(file *os.File) {
		_ = file.Close()
	}(file)

	return r.client.PutObject(r.ctx, &oss.PutObjectRequest{
		Bucket: oss.Ptr(r.bucket),
		Key:    oss.Ptr(object),
		Body:   file,
	})
}
func (r *Alibaba) ObjectDelete(object string) (*oss.DeleteObjectResult, error) {
	return r.client.DeleteObject(r.ctx, &oss.DeleteObjectRequest{
		Bucket: oss.Ptr(r.bucket),
	})
}

// #### 其它

func (r *Alibaba) ObjectCopy(source string, destination string) error {
	_, err := r.client.CopyObject(r.ctx, &oss.CopyObjectRequest{
		Bucket:       oss.Ptr(r.bucket),
		Key:          oss.Ptr(r.bucket),
		SourceBucket: oss.Ptr(r.bucket),
		SourceKey:    oss.Ptr(r.bucket),
	})
	return err
}

// #### 封装

func (r *Alibaba) ObjectMove(source string, destination string) error {
	if err := r.ObjectCopy(source, destination); err != nil {
		return err
	}

	_, err := r.ObjectDelete(source)
	return err
}
